#define _CRT_SECURE_NO_WARNINGS



#include <iostream>
#include <string>
#include <algorithm>
#include <assert.h>
#include <list>
using namespace std;

// 初始化 以及拷贝赋值
void test_string1() {
	//常用
	string s1; //定义
	string s2("hello world"); //拷贝构造
	string s3(s2);

	//不常用 了解
//从s2的第三个字符开始拷贝，拷贝5个字符，如果5大于后面的字符数，到'\0'停止
	string s4(s2, 3, 5);
	string s5(s2, 3); //从s2的第三个字符开始拷贝
	string s6(s2, 3, 30);
	string s7("hello world", 5);
	string s8(10, 'x');

	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
	cout << "s5 = " << s5 << endl;
	cout << "s6 = " << s6 << endl;
	cout << "s7 = " << s7 << endl;
	cout << "s8 = " << s8 << endl;
}

void test_string2()
{
	string s1("hello world"); //构造
	string s2 = "hello world"; //隐式类型转换
	const string& s3 = "hello world";// 临时对象具有常性，加const
 }

class String { //string遍历的实现
public: 
	// 引用返回的作用：
	// 1、减少拷贝
	// 2、修改拷贝对象
	char& operator[](size_t i)
	{
		assert(i < _size);
		return _str[i];
	}
private :
	char* _str;
	size_t _size;
	size_t capacity;
};

void test_string3()
{
	string s1("hello world"); //长度不算 '\0'
	cout << s1.size() << endl;
	cout << s1.length() << endl; //两者没啥区别

	for (size_t i = 0; i < s1.size(); i++)
	{
		s1[i]++;
		cout << s1[i] << " ";
	}
	cout << endl;
	s1[0] = 'x';
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1.operator[](i) << " ";
		//cout << s1[i] << " ";
	}

	cout << endl;
}

// 遍历
void test_string4() {
	// 遍历方式：下标 + []
	string s1 = "hello world";
	for (int i = 0; s1[i]; i++)
	{
		cout << s1[i] << " ";
	}
	cout << endl;

	//遍历方式2：迭代器 
	string::const_iterator it1 = s1.begin(); //const迭代器只读
	//auto it1 = s1.begin();
	while (it1 != s1.end())
	{
		//*it1 += 3;// 不能修改
		cout << *it1 << " ";
		++it1;
	}
	string::iterator it2 = s1.begin();
	while (it2 != s1.end()) { 
		cout << *it2 << " ";
		++it2;
	}
	cout << endl;

	cout << typeid(it2).name() << endl;
	
	//遍历方式3：范围for
	// 底层：就是迭代器
	for (auto e : s1) {
		cout << e << " ";
	}
}


void diedai()
{
	list <int> lt1;
	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(3);

	list<int>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << endl;
		it++;
	}
	cout << endl;
}

void test_string5() //反向迭代器
{
	string s1("hello world");
	string::reverse_iterator it1 = s1.rbegin();
	while (it1 != s1.rend()) {
		*it1 += 3;
		cout << *it1 << " ";
		++it1;
	}

	string::const_reverse_iterator it2 = s1.rbegin(); //const迭代器只读
	//auto it1 = s1.begin();
	while (it1 != s1.rend())
	{
		//*it1 += 3;// 不能修改
		cout << *it1 << " ";
		++it1;
	}
}

void test_string6()
{
	string s1("hello world");
	cout << s1 <<endl;

	//按字典序排序
	//sort(s1.begin(), s1.end());
	
	// 第一个和最后一个参与排序
	//sort(++s1.begin(), --s1.end());

	//前五个排序
	sort(s1.begin(), s1.begin() + 5);
	cout << s1 << endl;
}


void test_string7()
{
	string s1("hello world");
	cout << s1 << endl;

	s1.push_back('x');
	cout << s1 << endl;
	
	s1.append(" yyyyyy!! ");
	cout << s1 << endl;

	s1 += 'z';
	s1 += "wwwwww";
	cout << s1 << endl;
}

void test_string8()
{
	string s1("hello world");
	cout << s1 << endl;

	s1.assign("11111");// 等价与赋值
	cout << s1 << endl;

	// 慎用，因为效率不高 -> O(N)
	// 插入
	string s2("hello world"); 
	s2.insert(0, "xxxx");
	cout << s2 << endl;

	s2.insert(0, 2, 'y');
	cout << s2 << endl;

	s2.insert(s2.begin(), 'w');
	cout << s2 << endl;

	s2.insert(s2.begin(), s1.begin(), s1.end());
	cout << s2 << endl;

}

void test_string9()
{
	string s1("hello world");
	cout << s1 << endl;

	//慎用，因为效率不高，和insert类似
	s1.erase(0, 1);
	cout << s1 << endl;

	//s1.erase(5);// 删除第五个字符之后数据
	s1.erase(5, 100);//超过了有多少删多少
	cout << s1 << endl;

	//慎用，因为效率不高，和insert类似
	string s2("hello world");
	s2.replace(5, 1, "%20");
	cout << s2 << endl;
}

void TestPushBack() //s的扩容
{
	string s;
	size_t sz = s.capacity(); //capacity 比 实际空间少一个，有一个多的是预留给\0
	cout << "making s grow:\n ";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if(sz!=s.capacity()) {
			sz = s.capacity();
			cout << "capacity changed: " << sz << endl;
		}
	}
}


void test_string10() 
{
	string s1("hello world");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	cout << s1.max_size() << endl;

	TestPushBack();

	cout << s1.capacity() << endl;

	
}


// 文件操作
void TestFile()
{
	string file("test.cpp");
	FILE* fout = fopen(file.c_str(), "r");
	//.c_str()作用是吧一个string串转换成一个C - style的串，
	// 以"/0"null character结尾，返回的是一个指向该C - style串的常指针。
	char ch = fgetc(fout);
	while (ch != EOF)
	{
		cout << ch;
		ch = fgetc(fout);
	}
}

void test_string11()
{
	string s1;
	s1.resize(5, '0'); //初始值
	s1[4] = '3';
	s1[3] = '4';
	s1[2] = '5';
	s1[1] = '6';
	s1[0] = '7';

	cout << s1 << endl;

	// 再扩容
	s1.reserve(100);
	cout << s1.size() << "  " << s1.capacity() << endl;

	//reserve 在vs下不会缩容，没有规定
	s1.reserve(20);
	cout << s1.size() << "  " << s1.capacity() << endl;

	s1.resize(10);
	cout << s1.size() << "  " << s1.capacity() << endl;

	s1.resize(120);
	cout << s1.size() << "  " << s1.capacity() << endl;

	//由此发现resize影响capacity、size(当再开辟空间大于原先capacity才会影响capacity), reserve不影响size

	//插入（空间不够扩容）
	string s2("hello world");
	s2.resize(20, 'x'); //不会清掉之前的字符，在后面填写
	cout << s2 << endl;

	// 删除
	s2.resize(5); 


	//try {
	//	//访问
	//	//cout << s2[10] << endl;
	//	s2.at(10);
	//}
	//catch (const exception& e) {
	//	cout << e.what() << endl;
	//}

	//TestFile();
	
}


void test_string12()
{
	string s = "aabaabaab";
	cout << s.find("aa") << endl;//查找字符串“aa”首次出现位置 0
	cout << s.find("aa", 3) << endl;//查找下标3开始（即第四个字符开始）字符串“aa”首次出现位置  3
	cout << s.find('a') << endl;//查找字符串'a'首次出现位置  0
	cout << s.find('a', 3) << endl;//查找下标3开始（即第四个字符开始）字符串“aa”首次出现位置  3
	cout << s.rfind("aa") << endl;//查找字符串“aa”最后一次出现位置  6

	cout << s.find_first_of("hark") << endl;
	cout << s.find_last_of("a") << endl;

	cout << s.find_first_not_of("hark") << endl;
	cout << s.find_last_not_of("hark") << endl;

}

void test_string13()
{
	string a = "abc";
	string b = a;

	//a.c_str() == b.c_str()比较的是存储字符串位置的地址,
	// a和b是两个不同的对象，内部数据存储的位置也不相同，因此不相等
	if (a.c_str() == b.c_str())cout << "True" << endl;
	else cout << "False" << endl;
}


void test_string14()
{
	string file("string.cpp.zip"); //找到前缀和后缀
	size_t pos1 = file.find('.');
	size_t pos2 = file.rfind('.'); //后缀

	string suffix1 = file.substr(0, pos1);//获得前缀子串
	string suffix2 = file.substr(pos2);//获得后缀子串

	//string suffix = file.substr(pos2,file.size() - pos2);
	cout << "find = " << pos1 << " —— " << suffix1 << endl;
	cout << "rfind = " << pos2 << " —— " << suffix2 << endl;
}

void test_string15()
{
	string s1 = "hello";
	string s2 = " world";

	string ret1 = s1+s2;
	cout << ret1 << endl;

	string ret2 = s1 + "xxxxx";
	cout << ret2 << endl;

	string ret3 = "xxxx"+s1;
	cout << ret3 << endl;
}

void test_string16()
{
	int a = 10, b = 40;
	string s = to_string(a + b);
	cout << s << endl;
}


void test_string17()
{
	char buff1[] = "abcd";
	char buff2[] = "比特";
	string s1("abcd");

	cout << sizeof(buff1) << endl; // 5  '\0'算一个字节
	cout << sizeof(buff2) << endl; // 5,一个汉字两个字节,'\0'算一个字节
	cout << sizeof(s1) << endl; // 40

	cout << strlen(buff1) << endl; // 4
	cout << strlen(buff2) << endl; // 4,一个汉字两个字节
	//cout << strlen(s1) << endl; // 不能计算
}

int main()
{
	test_string17();


	return 0;
}
